﻿using AnalysisEnvironment.PackageProviders;
using AnalysisEnvironment.PackageProviders.Business;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace AnalysisEnvironment
{
    public class ProjectPackageInitOptions
    {
        public List<string> NugetUrls { get; set; }

        public List<string> NugetPaths { get; set; }

        public List<string> SearchPaths { get; set; }

        public string ProjectPath { get; set; }
    }

    public static class ProjectEnvironment
    {
        public static IDisposable BuildEnvironment(ProjectPackageInitOptions options)
        {
            return new ProjectEnv(options);
        }

        public class ProjectEnv : IDisposable
        {
            private List<IPackageProvider> PackageProviders { get; } = new List<IPackageProvider>();

            public ProjectEnv(ProjectPackageInitOptions options)
            {
                if (string.IsNullOrEmpty(options?.ProjectPath) != true)
                    PackageProviders.Add(new LocalFilePackageProvider(options.ProjectPath));

                if (options?.SearchPaths?.Any() == true)
                {
                    foreach (var item in options.SearchPaths)
                    {
                        PackageProviders.Add(new LocalFilePackageProvider(item));
                    }
                }

                if (options?.NugetPaths?.Any() == true)
                {
                    foreach (var item in options.NugetPaths)
                    {
                        PackageProviders.Add(new LocalNugetPackageProvider(item));
                    }
                }

                if (options?.NugetUrls?.Any() == true)
                {
                    PackageProviders.Add(new LocalNugetPackageProvider(RemoteNugetPackageProvider.PakcagePath));

                    foreach (var item in options.NugetUrls)
                    {
                        PackageProviders.Add(new RemoteNugetPackageProvider(item));
                    }
                }

                AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
            }

            public Assembly ResolveAssembly(object sender, ResolveEventArgs args)
            {
                AssemblyName assemblyName = new AssemblyName(args.Name);

                Console.WriteLine($"ResolveAssembly {assemblyName}");

                foreach (var item in PackageProviders)
                {
                    try
                    {
                        var assmbly = item.TryLoadAssembly(assemblyName);
                        if (assmbly != null)
                            return assmbly;
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"{item.GetType().Name} 在尝试提供 {assemblyName} 时出错");
                    }
                }

                return null;
            }

            bool IsDisposed = false;

            public void Dispose()
            {
                if (IsDisposed)
                    return;

                IsDisposed = true;

                AppDomain.CurrentDomain.AssemblyResolve -= ResolveAssembly;
            }

            ~ProjectEnv()
            {
                Dispose();
            }
        }
    }
}
